#version 330
in vec2 v_texCoord;
uniform usampler2D yTexture;
uniform usampler2D uvTexture;
uniform sampler3D lutTexture;
uniform float filterRatio;
uniform uint uvoffset;
out uvec4 FragColor;

uvec3 tex_yuv(ivec2 pos){
    uvec3 yuv;
    yuv.x = texelFetch(yTexture, pos, 0).r;
    yuv.y = texelFetch(uvTexture, pos / 2, 0).g;
    yuv.z = texelFetch(uvTexture, pos / 2, 0).r;
    return yuv;
}

vec3 bt_10bit_full_yuv_to_rgb(vec3 yuv){
    return mat3(
        1.000000, 1.0000000, 1.00000,
        0.000000, -0.344000, 1.77200,
        1.402000, -0.714000, 0.00000
    ) * (yuv - vec3(0.0, uvoffset, uvoffset));
}

vec3 bt_10bit_full_rgb_to_yuv(vec3 rgb){
    vec3 yuv = mat3(
        0.299000, -0.169000, 0.50000,
        0.587000, -0.331000, -0.4190,
        0.114000, 0.5000000, -0.0810
    ) * rgb;
    yuv.y += float(uvoffset);
    yuv.z += float(uvoffset);
    return yuv;
}

vec3 lut_cube_rgb(vec3 rgb){
    return vec3(mix(rgb, texture(lutTexture, rgb).rgb, filterRatio));
}

void main() {
    ivec2 yTexCoordInt = ivec2(ivec2(v_texCoord) * textureSize(yTexture, 0));
    uvec3 pre_yuv16 = tex_yuv(yTexCoordInt);
    vec3 pre_yuv10 = vec3(pre_yuv16 >> 6);
    vec3 rgb10 = bt_10bit_full_yuv_to_rgb(pre_yuv10);
    vec3 rgb = rgb10 / 1023.0;
    vec3 lut_rgb = lut_cube_rgb(rgb);
    uvec3 post_yuv10 = uvec3(bt_10bit_full_rgb_to_yuv(lut_rgb) * 1023);
    uvec3 post_yuv16 = post_yuv10 << 6;
    FragColor = uvec4(post_yuv16, 1.0);
}